package com.tumblr.anond2.solr.sql;

import java.util.List;
import java.util.Map;

import org.apache.solr.common.SolrDocumentList;

import com.google.common.base.Ascii;
import com.google.common.base.CharMatcher;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import static com.google.common.base.Preconditions.*;
import com.tumblr.anond2.solr.client.solrj.SolrRDBClient;

/**
 * Solr SQL Command.
 * 
 * <p>execute command format</p>
 * 
 * <p>"INSERT INTO user id username_s company_id VALUES 001 \"John Smith\" A01"</p>
 * <p>INSERT INTO [TABLE] [ID] COLUMN1 COLUMN2.. VALUES [ID] VALUE1 VALUE2..</p>
 * 
 * <p>"UPDATE user SET company_id_s=A03 WHERE id=001"</p>
 * <p>UPDATE [TABLE] SET COLUMN1=VALUE1 COLUMN2=VALUE2.. WHERE [id=XXX] [_version_=XXX]</p>
 * 
 * <p>"DELETE id=001 id=002"</p>
 * <p>DELETE [id=XXX] [id=XXX]</p>
 * 
 */
public class SolrSQLCommand {
	
	private SolrRDBClient client = null;
	
	private String sql = "";
	private String query = "";
	private Map<String, String> additionalParams = Maps.newHashMap();

	public SolrSQLCommand() throws Exception {
		this.client = SolrRDBClient.getInstance();
		init();
	}
	
	public SolrSQLCommand(String sql) throws Exception {
		this.client = SolrRDBClient.getInstance();
		checkNotNull(sql, "sql can't be null");
		this.sql = CharMatcher.WHITESPACE.trimAndCollapseFrom(sql,' ');
		init();
	}
	
	public boolean executeNonQuery() throws Exception{
		boolean rval = false;
		
		String[] terms = sql.split(" ");
		if (Ascii.toLowerCase(terms[0]).equals("insert")){
			rval = this.excecuteInsert(terms);
		}
		if (Ascii.toLowerCase(terms[0]).equals("update")){
			rval = this.excecuteUpdate(terms);
		}
		if (Ascii.toLowerCase(terms[0]).equals("delete")){
			rval = this.excecuteDelete(terms);
		}
		return rval;
	}
	
	public SolrDocumentList executeDocumentList() throws Exception{
		return this.excecuteSelect();
	}
	
	private boolean excecuteInsert(String[] terms) throws Exception {
		List<String> fields = Lists.newArrayList();
		List<Object> values = Lists.newArrayList();
		boolean tableExists = false;
		boolean valuesExists = false;
		boolean idExists = false;
		String id = "";
		String connectTerm = "";
		boolean connecting = false;
		for (String term : terms){
			if ((term.toLowerCase().equals("insert")) ||
				(term.toLowerCase().equals("into"))){
				tableExists = true;
				continue;
			}
			if (tableExists){
				fields.add("table_s"); values.add(term);
				tableExists = false;
				continue;
			}
			if (term.toLowerCase().equals("id")){
				continue;
			}
			if (term.toLowerCase().equals("values")){
				valuesExists = true;
				idExists = true;
				continue;
			}
			if (valuesExists && idExists){
				id = term;
				idExists = false;
				continue;
			}	
			if (valuesExists){
				if (term.endsWith("\"") && !connectTerm.equals("")){
					connectTerm = connectTerm + " " + term.substring(0, term.length() - 1);
					term = connectTerm;
					connecting = false;	
				}
				if (connecting){
					connectTerm = connectTerm + " " + term;
					continue;
				}
				if (term.startsWith("\"") && !term.endsWith("\"")){
					connectTerm = term.substring(1);
					connecting = true;
					continue;
				}
				if (term.startsWith("\"") && term.endsWith("\"")){
					term = term.substring(1, term.length() - 1);
				}
				values.add(term);
				continue;
			}			
			fields.add(term);
		}
		return client.add(id, fields, values);
	}
	
	private boolean excecuteUpdate(String[] terms) throws Exception {
		List<String> fields = Lists.newArrayList();
		List<Object> values = Lists.newArrayList();
		boolean tableExists = false;
		boolean setExists = false;
		boolean whereExists = false;
		String connectTerm = "";
		boolean connecting = false;
		boolean splitting = false;
		String id = null;
		Long version = 0L;
		for (String term : terms){
			if (term.toLowerCase().equals("update")){
				tableExists = true;
				continue;
			}
			if (tableExists){
				fields.add("table_s"); values.add(term);
				tableExists = false;
				continue;
			}
			if (term.toLowerCase().equals("set")){
				setExists = true;
				continue;
			}
			if (term.toLowerCase().equals("where")){
				setExists = false;
				whereExists = true;
				continue;
			}
			if (setExists && !whereExists){	
				if (!splitting){
					String[] block  = term.split("=");
					fields.add(block[0]);
					term = block[1];
					splitting = true;
				}
				if (term.endsWith("\"") && !connectTerm.equals("")){
					connectTerm = connectTerm + " " + term.substring(0, term.length() - 1);
					term = connectTerm;
					connecting = false;	
				}
				if (connecting){
					connectTerm = connectTerm + " " + term;
					continue;
				}
				if (term.startsWith("\"") && !term.endsWith("\"")){
					connectTerm = term.substring(1);
					connecting = true;
					continue;
				}
				if (term.startsWith("\"") && term.endsWith("\"")){
					term = term.substring(1, term.length() - 1);
				}
				values.add(term);
				splitting = false;
			}
			if (whereExists){
				String[] block = term.split("=");
				if (block[0].equals("id")) id = block[1];
				if (block[0].equals("_version_")) version = Long.parseLong(block[1]);
				if (id != null && version > 0L){
					whereExists = false;
				}
				continue;
			}			
		}
		return client.set(id, fields, values, version);
	}

	private boolean excecuteDelete(String[] terms) throws Exception{
		boolean idsExists = false;
		List<String> ids = Lists.newArrayList();
		for (String term : terms){
			if (term.toLowerCase().equals("delete")){
				idsExists = true;
				continue;
			}
			if (idsExists){
				String[] block = term.split("=");
				ids.add(block[1]);
				continue;
			}
		}
		return client.delete(ids);
	}
	
	private SolrDocumentList excecuteSelect() throws Exception{
		return client.get(query, additionalParams);
	}
	
	private void init(){
		query = "*:*";
		additionalParams.clear();
	}
	
	public void setQuery(String query){
		this.query = query;
	}
	
	public void setAdditionalParams(Map<String, String> additionalParams){
		this.additionalParams = additionalParams;
	}
}
